package com.oig.sys.auth.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.oig.common.constants.CommonEnum;
import com.oig.common.exception.BadRequestException;
import com.oig.common.util.JsonUtil;
import com.oig.sys.auth.constants.AuthConstants;
import com.oig.sys.auth.constants.AuthEnums;
import com.oig.sys.auth.dao.ITbResourceDao;
import com.oig.sys.auth.dao.ITbSystemDao;
import com.oig.sys.auth.dto.ResourceDto;
import com.oig.sys.auth.entity.TbResource;
import com.oig.sys.auth.entity.TbSystem;
import com.oig.sys.auth.service.*;
import com.oig.sys.auth.vo.PermissionVo;
import com.oig.sys.auth.vo.ResourceColumnVo;
import com.oig.sys.auth.vo.ResourceVo;
import com.oig.sys.security.util.SecurityUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author wuxl
 */
@Service
@Slf4j
public class TbResourceServiceImpl implements ITbResourceService {


	private final ITbResourceDao tbResourceDao;
	private final ITbSystemDao tbSystemDao;
	private final ITbResourceColumnService resourceColumnService ;
	private final ITbUserRoleService userRoleService;
	private final ITbResourcePermissionService resourcePermissionService;
	private final ITbRoleResourceService roleResourceService;
	private final ITbRolePermissionService rolePermissionService;
	private final RedisTemplate<String, Object> redisTemplate;

	@Autowired
	public TbResourceServiceImpl(ITbResourceDao tbResourceDao,
								 ITbSystemDao tbSystemDao,
								 ITbResourceColumnService resourceColumnService,
								 ITbUserRoleService userRoleService,
								 ITbResourcePermissionService resourcePermissionService,
								 ITbRoleResourceService roleResourceService,
								 ITbRolePermissionService rolePermissionService,
								 RedisTemplate<String, Object> redisTemplate) {
		this.tbResourceDao = tbResourceDao;
		this.tbSystemDao = tbSystemDao;
		this.resourceColumnService = resourceColumnService;
		this.userRoleService = userRoleService;
		this.resourcePermissionService = resourcePermissionService;
		this.roleResourceService = roleResourceService;
		this.rolePermissionService = rolePermissionService;
		this.redisTemplate = redisTemplate;
	}


	@Override
	public ResourceVo getResourceInfo(Integer resourceId) {
		List<Integer> idList = new ArrayList<>();
		idList.add(resourceId);
		List<ResourceVo> resourceVoList = tbResourceDao.findSystemMenuByIdList(idList);
		if (resourceVoList==null||resourceVoList.isEmpty()){
			throw new BadRequestException("resourceId错误");
		}
		ResourceVo resourceVo = resourceVoList.get(0);
		resourceVo.setPermissionList(this.resourcePermissionService.findPermissionId(resourceId));
		resourceVo.setResourceColumnList(this.resourceColumnService.findAllColumnByResourceId(resourceId));
		return resourceVo;
	}

	@Override
	public ResourceVo getResourceInfo(String resourceCode, Integer userId) {
		ResourceVo resourceVo = getResourceCache(resourceCode);
		if (Objects.isNull(resourceVo)){
			TbResource resource = this.tbResourceDao.getByResourceCode(resourceCode);
			if (resource == null) return null;
			resourceVo = BeanUtil.copyProperties(resource,ResourceVo.class);
		}
		if (userId!=null&&userId>0){
			resourceVo.setResourceColumnList(this.resourceColumnService.findAllColumnByResourceId(resourceVo.getId(), userId, false));
		} else {
			resourceVo.setResourceColumnList(this.resourceColumnService.findAllColumnByResourceId(resourceVo.getId()));
		}
		return resourceVo;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public ResourceVo addResource(ResourceDto resourceDto) {
		log.debug("dto={},",resourceDto);
		TbResource resource = new TbResource();
		BeanUtils.copyProperties(resourceDto, resource, "id");
		resource.setCreateTime(new Date());
		resource.setCreateUserName(SecurityUtil.getDefineUserMain().getRealName());
		resource.setCreateUserId(SecurityUtil.getDefineUserMain().getId());
		if (resource.getParentId()==null||resource.getParentId()==0){
			resource.setParentId(0);
			resource.setLevel(1);
			if (CommonEnum.FlagEnum.TRUE_FLAG.getCode().equals(resource.getIsQueryOnly())){
				throw new BadRequestException("一级菜单，不能设为直接查询");
			}
		} else {
		    TbResource parent = this.tbResourceDao.getTbResourceById(resource.getParentId());
		    if (CommonEnum.FlagEnum.TRUE_FLAG.getCode().equals(parent.getIsQueryOnly())){
		    	throw new BadRequestException("父菜单是查询界面，不能加下级");
			}
		    resource.setLevel(parent.getLevel()+1);
        }
		resource.setStatus(CommonEnum.CommonStatusEnum.OK.getCode());
		if (StringUtils.isBlank(resourceDto.getNoDelFlag())){
			resource.setNoDelFlag(CommonEnum.FlagEnum.TRUE_FLAG.getCode());
		}
		if (StringUtils.isBlank(resource.getIsQueryOnly())){
			resource.setIsQueryOnly(CommonEnum.FlagEnum.FALSE_FLAG.getCode());
		}
		if (StringUtils.isBlank(resource.getIsPublicData())){
			resource.setIsPublicData(AuthEnums.DataScope.TAN.getCode());
		}
		if (resource.getSort()==null){
			Integer ms = this.tbResourceDao.findMaxSortByParentId(resource.getSystemId(), resource.getParentId());
			if (ms==null)ms=0;
			resource.setSort(ms+1);
		}
		TbResource cacheResource = this.tbResourceDao.save(resource) ;

		ResourceVo resourceVo = new ResourceVo();
		BeanUtils.copyProperties(resource,resourceVo);
		//对应菜单，查询列表，显示的列存储起来便于个性显示配置
		if (resourceDto.getResourceColumnList()!=null && !resourceDto.getResourceColumnList().isEmpty()){
			List<ResourceColumnVo> resourceColumnVoList = resourceColumnService.addResourceColumn(resource.getId(),
					resourceDto.getResourceColumnList()) ;
			resourceVo.setResourceColumnList(resourceColumnVoList);
		}
		//对应功能 所需权限列表
		if (resourceDto.getPermissionList()!=null && !resourceDto.getPermissionList().isEmpty()){
			List<PermissionVo> permissionVoList =resourcePermissionService.addResourcePermission(resource.getId(),
					resource.getSystemId(), resourceDto.getPermissionList());
			resourceVo.setPermissionList(permissionVoList);
			if (permissionVoList!=null && !permissionVoList.isEmpty()){
				//更新角色权限
				this.addAllRoleNewPermission(resource.getId(), permissionVoList);
			}
		}

		// 同步缓存
		setResourceCache(cacheResource.getResourceCode(), BeanUtil.copyProperties(cacheResource, ResourceVo.class));
		return resourceVo;
	}

	private void addAllRoleNewPermission(Integer resourceId, List<PermissionVo> permissionVoList){
		List<Integer> roleIdList = roleResourceService.findRoleIdByResourceId(resourceId);
		rolePermissionService.addAllRoleNewPermission(roleIdList, permissionVoList);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public ResourceVo updateResource(ResourceDto resourceDto) {
		TbResource resource = this.tbResourceDao.getTbResourceById(resourceDto.getId()) ;
		log.debug("dto={},entity={}",resourceDto,resource);
		if (resource==null){
			throw new BadRequestException("按钮菜单不存在") ;
		}
		if (StringUtils.isBlank(resourceDto.getIsPublicData())){		//防止，前端版本没有跟上前，这个字段被设置为null
			resourceDto.setIsPublicData(resource.getIsPublicData());
		}
		if (StringUtils.isBlank(resourceDto.getIsQueryOnly())){
			resourceDto.setIsQueryOnly(resource.getIsQueryOnly());
		}
		if (StringUtils.isBlank(resourceDto.getNoDelFlag())){
			resourceDto.setNoDelFlag(resource.getNoDelFlag());
		}
		BeanUtils.copyProperties(resourceDto, resource, "id", "status","level");
		resource.setLastUpdateName(SecurityUtil.getDefineUserMain().getRealName());
		resource.setLastUpdateId(SecurityUtil.getDefineUserMain().getId());
		resource.setLastUpdateTime(new Date());

		TbResource cacheResource = this.tbResourceDao.save(resource) ;
		ResourceVo resourceVo = new ResourceVo();
		BeanUtils.copyProperties(resource,resourceVo);
		//对应菜单，查询列表，显示的列存储起来便于个性显示配置
		if (resourceDto.getResourceColumnList()!=null && !resourceDto.getResourceColumnList().isEmpty()){
			List<ResourceColumnVo> resourceColumnVoList = resourceColumnService.updateResourceColumnByCode(resource.getId(),
					resourceDto.getResourceColumnList()) ;
			resourceVo.setResourceColumnList(resourceColumnVoList);
		}
		//对应功能 所需权限列表
		if (resourceDto.getPermissionList()!=null && !resourceDto.getPermissionList().isEmpty()){
			List<PermissionVo> permissionVoList =resourcePermissionService.updateResourcePermission(resource.getId(),
					resource.getSystemId(), resourceDto.getPermissionList());
			resourceVo.setPermissionList(permissionVoList);
			if (permissionVoList!=null && !permissionVoList.isEmpty()){
				//更新角色权限 不常用功能，不管效率了
				this.addAllRoleNewPermission(resource.getId(), permissionVoList);
			}
		}

		// 同步缓存
		setResourceCache(cacheResource.getResourceCode(), BeanUtil.copyProperties(cacheResource, ResourceVo.class));
		return resourceVo;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void cancelResource(Integer resourceId) {
		TbResource resource = this.tbResourceDao.getTbResourceById(resourceId) ;
		if (resource==null){
			throw new BadRequestException("按钮菜单不存在") ;
		}
		if (CommonEnum.FlagEnum.FALSE_FLAG.getCode().equals(resource.getNoDelFlag())){
			throw new BadRequestException("不允许删除") ;
		}
		resource.setStatus(CommonEnum.CommonStatusEnum.DEL.getCode());
		this.tbResourceDao.save(resource) ;

		// 删除缓存
		delResourceCache(resource.getResourceCode());
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void revertResource(Integer resourceId) {
		TbResource resource = this.tbResourceDao.getTbResourceById(resourceId) ;
		if (resource==null){
			throw new BadRequestException("按钮菜单不存在") ;
		}
		if (!CommonEnum.CommonStatusEnum.DEL.getCode().equals(resource.getStatus())){
			throw new BadRequestException("按钮菜单非注销状态") ;
		}
		resource.setStatus(CommonEnum.CommonStatusEnum.OK.getCode());
		TbResource cacheResource = this.tbResourceDao.save(resource) ;

		// 同步缓存
		setResourceCache(cacheResource.getResourceCode(), BeanUtil.copyProperties(cacheResource, ResourceVo.class));
	}

	@Transactional
	@Override
	public void delResource(Integer resourceId) {
		TbResource resource = this.tbResourceDao.getTbResourceById(resourceId) ;
		if (resource==null){
			throw new BadRequestException("按钮菜单不存在") ;
		}
		if (!CommonEnum.CommonStatusEnum.DEL.getCode().equals(resource.getStatus())){
			throw new BadRequestException("注销的才能彻底清除数据") ;
		}
		if (resource.getLevel()==2){
			this.resourceColumnService.delAllColumnByResourceId(resourceId);
			//resourceDataCfg 不删
			//resourceQltmp  不删
		}
		this.resourcePermissionService.delByResourceId(resourceId);
		this.roleResourceService.delRoleResourceByResourceId(resourceId);
		this.tbResourceDao.delete(resource);
	}

	@Override
	public List<ResourceVo> findResourceTree(Integer systemId) {
		List<ResourceVo> resourceList ;
		if (SecurityUtil.getDefineUserMain().getTenantId()==0){
			resourceList = this.tbResourceDao.findSystemMenu(systemId) ;
		} else {
			resourceList = this.userRoleService.findAllOkResourceVo(SecurityUtil.getDefineUserMain().getId(), systemId);
		}
		if (resourceList!=null){
			return buildOwnTree(0, resourceList);
		}
		return null;
	}

	private List<ResourceVo> buildOwnTree(Integer parentId, List<ResourceVo> resourceList){
		List<ResourceVo> childList = new ArrayList<>();
		for(Iterator<ResourceVo> iter = resourceList.iterator(); iter.hasNext();){	//用iterator可以移除元素
			ResourceVo resourceVo = iter.next();
			if(parentId.equals(resourceVo.getParentId())){		//找到儿子节点
				iter.remove(); 				//从orgzInfoList移除掉
				childList.add(resourceVo);	//儿子列表
			}
		}
		//循环完之后，再循环刚刚的儿子列表，找出他们各自的儿子列表,这样应该递归不会太深
		for(ResourceVo node  : childList){
			node.setChildren(this.buildOwnTree(node.getId(), resourceList));
		}
		//log.debug(" resourceList size ={}", resourceList.size());
		return childList;
	}


//
//	private ResourceVo buildTopNode(Integer systemId){
//		ResourceVo resourceVo = new ResourceVo();
//		resourceVo.setId(0);
//		resourceVo.setResourceCode(String.valueOf(systemId));
//		resourceVo.setResourceName(this.systemService.getSystem(systemId).getSystemName());
//		return resourceVo;
//	}
//
//	private TreeNode<ResourceVo> buildTreeNode(Integer systemId, List<ResourceVo> resourceList){
//		TreeNode<ResourceVo> treeNode = new TreeNode<>();
//		ResourceVo topNodeVo = this.buildTopNode(systemId);
//		treeNode.setNode(topNodeVo);
//		if (resourceList!=null){
//			log.debug(" parent resourceList size ={}", resourceList.size());
//			treeNode.setChild(this.buildTree(topNodeVo, resourceList));
//		}
//		return treeNode;
//	}

	@Override
	public List<ResourceVo> findUserResourceTree(Integer systemId) {
		log.info("findUserResourceTree userId={}", SecurityUtil.getDefineUserMain().getId());
		List<ResourceVo> resourceList ;
		TbSystem system = this.tbSystemDao.getTbSystemById(systemId);
		if (AuthEnums.SystemTypeEnum.SYSTEM_PUB.getCode().equals(system.getSystemType())){
			resourceList = this.tbResourceDao.findSystemMenuByStatus(systemId, CommonEnum.CommonStatusEnum.OK.getCode());
		} else {
			resourceList = this.userRoleService.findAllOkResourceVo(SecurityUtil.getDefineUserMain().getId(), systemId) ;
		}
		if (resourceList!=null){
			return buildOwnTree(0, resourceList);
		}
		return null;
	}


//	private List<TreeNode<ResourceVo>> buildTree(ResourceVo parentNode, List<ResourceVo> resourceList){
//		List<TreeNode<ResourceVo>> childlist = new ArrayList<>();
//		for(Iterator<ResourceVo> iter = resourceList.iterator(); iter.hasNext();){	//用iterator可以移除元素
//			ResourceVo resourceVo = iter.next();
//			if(parentNode.getId().equals(resourceVo.getParentId())){		//找到儿子节点
//				iter.remove(); 		//从orgzInfoList移除掉
//				TreeNode<ResourceVo> node = new TreeNode<>();	//创建一个节点
//				node.setNode(resourceVo);	//节点元素
//				node.setOrdinal(resourceVo.getSort());
//				childlist.add(node);//儿子列表
//			}
//		}
//		//循环完之后，再循环刚刚的儿子列表，找出他们各自的儿子列表,这样应该递归不会太深
//		for(TreeNode<ResourceVo> node  : childlist){
//			node.setChild(this.buildTree(node.getNode(), resourceList));
//		}
//		log.debug(" resourceList size ={}", resourceList.size());
//		return childlist;
//	}

	@Transactional
	@Override
	public void delResourceBySystemId(Integer systemId) {
		List<Integer> idList = this.tbResourceDao.findAllIdBySystemId(systemId);
		if (idList!=null && !idList.isEmpty()){
			for (Integer id : idList){
				this.delResource(id);
			}
		}
	}

	private void setResourceCache(String resourceCode, ResourceVo resourceVo) {
		String key = String.format(AuthConstants.AUTH_RESOURCE_REDIS_CODE_PREFIX, resourceCode);
		if (Objects.nonNull(resourceVo)){
			String value = JsonUtil.toJSONString(resourceVo);
			log.debug("setResourceCache resourceCode is {}", resourceCode);
			redisTemplate.opsForValue().set(key, value);
		}
	}
	private ResourceVo getResourceCache(String resourceCode) {
		try {
			String key = String.format(AuthConstants.AUTH_RESOURCE_REDIS_CODE_PREFIX, resourceCode);
			Object value = redisTemplate.opsForValue().get(key);
			if (Objects.nonNull(value)){
				log.debug("getResourceCache resourceCode is {}", resourceCode);
				return JsonUtil.toObject(value.toString(), ResourceVo.class);
			}
		} catch (Exception e) {
			log.error("getResourceCache fail, resourceCode is {}", resourceCode);
		}
		return null;
	}
	private void delResourceCache(String resourceCode) {
		log.debug("delResourceCache resourceCode is {}", resourceCode);
		String key = String.format(AuthConstants.AUTH_RESOURCE_REDIS_CODE_PREFIX, resourceCode);
		redisTemplate.opsForValue().getAndDelete(key);
	}
}
